home *** CD-ROM | disk | FTP | other *** search
- Path: abcfd20.larc.nasa.gov!amiga-request
- From: amiga-request@abcfd20.larc.nasa.gov (Amiga Sources/Binaries Moderator)
- Subject: v90i283: SnoopDos 1.00 - Monitors calls to AmigaDOS functions, Part02/02
- Reply-To: Eddy Carroll <ECARROLL@vax1.tcd.ie>
- Newsgroups: comp.sources.amiga
- Message-ID: <comp.sources.amiga:v90i283@abcfd20.larc.nasa.gov>
- References: <comp.sources.amiga:v90i282@abcfd20.larc.nasa.gov>
- Date: 14 Oct 90 19:07:11 GMT
- Approved: tadguy@uunet.UU.NET (Tad Guy)
- X-Mail-Submissions-To: amiga@uunet.uu.net
- X-Post-Discussions-To: comp.sys.amiga
-
- Submitted-by: Eddy Carroll <ECARROLL@vax1.tcd.ie>
- Posting-number: Volume 90, Issue 283
- Archive-name: util/snoopdos-1.0/part02
-
- #!/bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 2)."
- # Contents: snoopdos.c
- # Wrapped by tadguy@abcfd20 on Sun Oct 14 15:07:02 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'snoopdos.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'snoopdos.c'\"
- else
- echo shar: Extracting \"'snoopdos.c'\" \(32250 characters\)
- sed "s/^X//" >'snoopdos.c' <<'END_OF_FILE'
- X/*
- X * SNOOPDOS.C
- X *
- X * (C) Copyright Eddy Carroll, May 1990. Freely distributable.
- X *
- X * Snoopdos patches into dos.library and outputs a message to a
- X * debugging window or file whenever a process calls certain DOS
- X * functions.
- X *
- X * Type snoopdos -h for a list of available options. See the
- X * documentation for further details.
- X *
- X * Compiles under Lattice C V5.04. I use flags: -cusq -j88i -ms -v
- X */
- X
- X#ifndef LATTICE_50
- X#include "system.h"
- X#endif
- X
- X/*
- X * Assorted strings
- X */
- X#define TITLE \
- X"SnoopDos V1.0 (C) Copyright Eddy Carroll, Sept 1990. Freely distributable."
- X
- Xchar *HEADER =
- X"Process name Func Filename Mode Res."
- X"\r\n"
- X"------------ ---- -------- ---- ----"
- X"\r\n";
- X
- X#define PORTNAME "SnoopDos Port"
- X
- X#define DEFWINDOW "CON:0/0/640/120/"
- X
- X/*
- X * The following message array contains both colour and non-colour
- X * versions of the various short message strings displayed.
- X */
- Xchar *msgs[][2] = {
- X/* Monochrome Colour */
- X/* ---------- ------ */
- X "OLD ", "OLD ",
- X "NEW ", "\033[33mNEW\033[0m ",
- X "R/W ", "\033[32mR/W\033[0m ",
- X "??? ", "??? ",
- X "SHAR", "SHAR",
- X "EXCL", "\033[33mEXCL\033[0m",
- X "????", "????",
- X "Okay\r\n", "Okay\r\n",
- X "Fail\r\n", "\033[33mFail\033[0m\r\n",
- X ">", "\033[33m>\033[0m",
- X "> (Done)", "> (Done)",
- X "Warning: Missed", "\033[33mWarning:\033[0m Missed",
- X ">>>>\r\n", ">>>>\r\n",
- X "Open", "Open",
- X "Lock", "\033[33mLock\033[0m",
- X "Load", "\033[32mLoad\033[0m",
- X "Exec", "\033[32mExec\033[0m",
- X "CD ", "CD ",
- X "Del ", "\033[33mDel\033[0m "
- X};
- X
- X#define TXT_OLD msgs[ 0][colour]
- X#define TXT_NEW msgs[ 1][colour]
- X#define TXT_R_W msgs[ 2][colour]
- X#define TXT_QM3 msgs[ 3][colour]
- X#define TXT_SHAR msgs[ 4][colour]
- X#define TXT_EXCL msgs[ 5][colour]
- X#define TXT_QM4 msgs[ 6][colour]
- X#define TXT_OKAY msgs[ 7][colour]
- X#define TXT_FAIL msgs[ 8][colour]
- X#define TXT_POINT msgs[ 9][colour]
- X#define TXT_DONE msgs[10][colour]
- X#define TXT_WARN msgs[11][colour]
- X#define TXT_NEST msgs[12][colour]
- X#define TXT_OPEN msgs[13][colour]
- X#define TXT_LOCK msgs[14][colour]
- X#define TXT_LOAD msgs[15][colour]
- X#define TXT_EXEC msgs[16][colour]
- X#define TXT_CURDIR msgs[17][colour]
- X#define TXT_DELETE msgs[18][colour]
- X
- X#define POINT(x) ((x) ? TXT_POINT : " ")
- X
- X/*
- X * Now some standard system-type macros
- X */
- X#define reg_d0 register __d0
- X#define reg_d1 register __d1
- X#define reg_d2 register __d2
- X#define reg_d3 register __d3
- X#define reg_a0 register __a0
- X
- X#define BTOC(x) (void *)(((ULONG)x) << 2)
- X
- X#define D_S(name, type) char c_##name[sizeof(type)+3];\
- X type *name = (type *)((long)(c_##name+3) & ~3)
- X
- Xextern __asm BPTR CallOpen(reg_d1 UBYTE *, reg_d2 int);
- Xextern __asm BPTR CallLock(reg_d1 UBYTE *, reg_d2 int);
- Xextern __asm BPTR CallLoadSeg(reg_d1 UBYTE *);
- Xextern __asm LONG CallExecute(reg_d1 UBYTE *, reg_d2 BPTR, reg_d3 BPTR);
- Xextern __asm BPTR CallCurrentDir(reg_d1 BPTR);
- Xextern __asm LONG CallDeleteFile(reg_d1 UBYTE *);
- X
- X/*
- X * Structure used to pass messages back and fro
- X */
- Xtypedef struct {
- X struct Message msg; /* Standard message header */
- X struct Process *process; /* Sending process id */
- X int msgtype; /* Message type, see below */
- X int data1; /* Data field 1 */
- X void *data2; /* Data field 2 */
- X} MYMSG;
- X
- X/*
- X * Now the various settings that can be set to affect the monitoring
- X */
- Xtypedef struct {
- X int set_doopen; /* If true, monitor Open() */
- X int set_dolock; /* If true, monitor Lock() */
- X int set_doloadseg; /* If true, monitor LoadSeg() */
- X int set_doexecute; /* If true, monitor Execute() */
- X int set_docurdir; /* If true, monitor CurrentDir() */
- X int set_dodelete; /* If true, monitor DeleteFile() */
- X int set_showfullpath; /* If true, display full paths */
- X int set_sleepwait; /* If true, sleep if necessary */
- X int set_snoopactive; /* If true, monitoring is active */
- X int set_colour; /* If true, use ANSI colour codes */
- X} SETTINGS;
- X
- X/*
- X * Default settings
- X */
- XSETTINGS settings = { 1, 0, 1, 1, 1, 1, 0, 0, 1, 1 };
- X
- X/*
- X * These defines allow the various settings to be accessed as
- X * normal variables rather than structure members; this is purely
- X * for convenience.
- X */
- X#define doopen settings.set_doopen
- X#define dolock settings.set_dolock
- X#define doloadseg settings.set_doloadseg
- X#define doexecute settings.set_doexecute
- X#define docurdir settings.set_docurdir
- X#define dodelete settings.set_dodelete
- X#define showfullpath settings.set_showfullpath
- X#define sleepwait settings.set_sleepwait
- X#define snoopactive settings.set_snoopactive
- X#define colour settings.set_colour
- X
- X/*
- X * Now the various message types that can be sent
- X */
- Xtypedef enum {
- X MSG_QUIT, /* Quit */
- X MSG_GETOPTIONS, /* Read options */
- X MSG_SETOPTIONS, /* Update options */
- X MSG_OPEN, /* Open file */
- X MSG_OPEN_DONE, /* Open file completed */
- X MSG_LOCK, /* Lock file */
- X MSG_LOCK_DONE, /* Lock file completed */
- X MSG_LOADSEG, /* LoadSeg file */
- X MSG_LOADSEG_DONE, /* LoadSeg file completed */
- X MSG_EXECUTE, /* Execute command */
- X MSG_CURDIR, /* CurrentDir */
- X MSG_DELETE, /* DeleteFile */
- X MSG_DELETE_DONE, /* DeleteFile completed */
- X} MSGTYPES;
- X
- Xstruct SignalSemaphore sem[1];
- Xstruct MsgPort *myport; /* Pointer to background SnoopDos msg port */
- Xstruct MsgPort *inport; /* Pointer to our own message port */
- Xstruct Task *snooptask; /* Pointer to our own task */
- XBPTR debugwin; /* Output file or window */
- XBPTR stderr; /* Standard CLI console */
- Xint extfile; /* True if output directed to external file */
- Xchar extfilename[100]; /* Name of window/file to open if specified */
- Xchar outbuf[800]; /* Output buffer used by myprintf() etc. */
- X
- Xint missed_open_sig; /* Signal to indicate Open() missed */
- Xint missed_lock_sig; /* Signal to indicate Lock() missed */
- Xint missed_loadseg_sig; /* Signal to indicate LoadSeg() missed */
- Xint missed_execute_sig; /* Signal to indicate Execute() missed */
- Xint missed_curdir_sig; /* Signal to indicate CurrentDir() missed */
- Xint missed_delete_sig; /* Signal to indicate DeleteFile() missed */
- Xint portsig; /* Signal used by our public port */
- X
- X/**************************** Start of Functions ****************************/
- X
- X/*
- X * cleanup()
- X * ---------
- X * Cleans up all active resources and exits. If err is -1, then
- X * returns instead of exiting.
- X */
- Xvoid cleanup(int err)
- X{
- X static int called = 0;
- X
- X if (called++) /* Make sure not called twice by accident */
- X return;
- X
- X if (inport)
- X DeletePort(inport);
- X
- X if (debugwin)
- X Close(debugwin);
- X
- X if (stderr)
- X Close(stderr);
- X
- X if (err != -1)
- X exit(err);
- X}
- X
- X/*
- X * myprintf(), myfprintf()
- X * -----------------------
- X * Two low cost alternatives to printf that go directly to AmigaDOS
- X * Note we deliberately use the pre-ANSI declaration, to avoid Lattice
- X * kicking up a fuss about the wrong number of parameters.
- X */
- Xvoid myprintf(format, p1, p2, p3, p4, p5, p6)
- XUBYTE *format;
- XULONG p1, p2, p3, p4, p5, p6;
- X{
- X sprintf(outbuf, format, p1, p2, p3, p4, p5, p6);
- X Write(Output(), outbuf, strlen(outbuf));
- X}
- X
- Xvoid myfprintf(file, format, p1, p2, p3, p4, p5, p6)
- XBPTR file;
- Xchar *format;
- XULONG p1, p2, p3, p4, p5, p6;
- X{
- X sprintf(outbuf, format, p1, p2, p3, p4, p5, p6);
- X Write(file, outbuf, strlen(outbuf));
- X}
- X
- X#define printf myprintf
- X#define fprintf myfprintf
- X
- X/*
- X * sendmsg()
- X * ---------
- X * Sends a message to myport, and waits for a reply to arrive.
- X * A message type and some message data are all that need be provided
- X * by the caller; the callee will provide the rest. Doesn't return
- X * until a reply has been received.
- X */
- Xvoid sendmsg(int type, int data1, void *data2)
- X{
- X MYMSG msg;
- X struct Process *me = (struct Process *)FindTask(0);
- X struct MsgPort *replyport = &me->pr_MsgPort;
- X
- X msg.msg.mn_Node.ln_Type = NT_MESSAGE;
- X msg.msg.mn_Length = sizeof(MYMSG);
- X msg.msg.mn_ReplyPort = replyport;
- X msg.process = me;
- X msg.msgtype = type;
- X msg.data1 = data1;
- X msg.data2 = data2;
- X
- X PutMsg(myport, &msg);
- X WaitPort(replyport);
- X GetMsg(replyport);
- X}
- X
- X
- X/*
- X * getlockpath()
- X * -------------
- X * Returns a pointer to a string containing the full path for the
- X * specified lock. You must copy the string before calling this
- X * routine again.
- X */
- Xchar *getlockpath(BPTR lock)
- X{
- X struct Process *p = (struct Process *)FindTask(0L);
- X APTR oldwin = p->pr_WindowPtr;
- X static char path[300];
- X int pos = 299;
- X BPTR mylock;
- X char *name;
- X D_S(fib, struct FileInfoBlock);
- X int err = 0;
- X
- X p->pr_WindowPtr = (APTR)-1; /* Disable error requesters */
- X mylock = DupLock(lock);
- X
- X path[pos] = '\0';
- X
- X do {
- X int len;
- X BPTR newlock;
- X
- X if (!Examine(mylock, fib))
- X err++;
- X name = fib->fib_FileName;
- X if (*name == '\0')
- X name = "RAM"; /* Workaround for old RAM: disk bug */
- X len = strlen(name);
- X pos = pos - len - 1;
- X newlock = ParentDir(mylock);
- X UnLock(mylock);
- X mylock = newlock;
- X strncpy(path + pos, name, len);
- X if (mylock)
- X path[pos + len] = '/';
- X else
- X path[pos + len] = ':';
- X } while (mylock);
- X p->pr_WindowPtr = oldwin; /* Enable error requesters again */
- X
- X if (err) {
- X /*
- X * Volume not present so have to be happy with just
- X * returning the volume node instead.
- X */
- X struct FileLock *fl = BTOC(lock);
- X struct DeviceList *dl = BTOC(fl->fl_Volume);
- X UBYTE *name = BTOC(dl->dl_Name);
- X
- X strncpy(path, name + 1, *name);
- X path[*name] = '\0';
- X strcat(path, ":.../");
- X return (path);
- X } else
- X return (path + pos);
- X}
- X
- X/*
- X * makepath()
- X * ----------
- X * Builds a full path string given a process ptr and a filename.
- X * If the filename includes relative references (// or :)
- X * these are handled also. The point of this is to resolve relative
- X * directory references.
- X *
- X * Returns TRUE if a new string was generated, FALSE if the existing
- X * string didn't depend on the current directory (this doesn't affect
- X * the output stored in buf though).
- X */
- Xint makepath(char *buf, BPTR curdir, char *filename)
- X{
- X char *origfilename = filename;
- X int pos;
- X int doneroot = 0;
- X
- X /*
- X * Special check for the 'current process console' file '*'
- X */
- X if (strcmp(filename, "*") == 0) {
- X strcpy(buf, filename);
- X return (FALSE);
- X }
- X
- X strcpy(buf, getlockpath(curdir));
- X pos = strlen(buf);
- X
- X for (;;) {
- X if (!doneroot && *filename == ':') {
- X /*
- X * Path is relative to root
- X */
- X doneroot = 1;
- X for (pos = 0; buf[pos] && buf[pos] != ':'; pos++)
- X ;
- X if (buf[pos] == ':')
- X pos++;
- X } else if (*filename == '/') {
- X /*
- X * Path is relative to parent directory; if none, then
- X * remains the same.
- X */
- X int newpos = pos - 2;
- X while (newpos >= 0 && buf[newpos] != '/' && buf[newpos] != ':')
- X newpos--;
- X if (newpos >= 0)
- X pos = newpos + 1;
- X } else {
- X /*
- X * No more special characters; just append what's left of
- X * the filename.
- X */
- X if (!doneroot) {
- X /*
- X * If the filename wasn't relative to the root
- X * directory, then make sure there are no device/volume
- X * references contained within it. We copy the original
- X * filename rather than the currently modified version
- X * since a volume name of /A: is legal and the / would
- X * be stripped off the modified name.
- X */
- X char *p;
- X for (p = filename; *p; p++) {
- X if (*p == ':') {
- X strcpy(buf, origfilename);
- X return (0);
- X }
- X }
- X }
- X strcpy(buf + pos, filename);
- X return (1);
- X }
- X filename++;
- X }
- X}
- X
- X/*
- X * OutputLine()
- X * ------------
- X * Outputs a line of text in the main window, according to the
- X * truncation mechanism used.
- X */
- X
- X/*
- X * mainloop()
- X * ----------
- X * This is the main event loop for SnoopDOS, where everything happens.
- X * Control is passed here when SnoopDOS first starts up. When this
- X * function returns, it terminates the background process.
- X */
- Xvoid mainloop(void)
- X{
- X static char fullname[300];
- X int done = 0; /* True if finished processing */
- X int col0 = 1; /* True if cursor in column 0 */
- X int nested = 0; /* True if nested DOS calls */
- X
- X#define MISSED_NONE 0 /* Haven't missed anything */
- X#define MISSED_OPEN (1 << 0) /* Missed Open() call */
- X#define MISSED_LOCK (1 << 1) /* Missed Lock() call */
- X#define MISSED_LOADSEG (1 << 2) /* Missed LoadSeg() call */
- X#define MISSED_EXECUTE (1 << 3) /* Missed Execute() call */
- X#define MISSED_CURDIR (1 << 4) /* Missed CurrentDir() call */
- X#define MISSED_DELETE (1 << 5) /* Missed DeleteFile() call */
- X
- X int missed = MISSED_NONE; /* Was a DOS function missed? See above */
- X
- X inport = CreatePort(PORTNAME, 0);
- X if (!inport) {
- X fprintf(stderr, "SnoopDos: Can't allocate message port.\n");
- X cleanup(-1);
- X return;
- X }
- X
- X myport = inport;
- X portsig = 1 << myport->mp_SigBit;
- X
- X /*
- X * Allocate signals
- X */
- X missed_open_sig = 1 << AllocSignal(-1);
- X missed_lock_sig = 1 << AllocSignal(-1);
- X missed_loadseg_sig = 1 << AllocSignal(-1);
- X missed_execute_sig = 1 << AllocSignal(-1);
- X missed_curdir_sig = 1 << AllocSignal(-1);
- X missed_delete_sig = 1 << AllocSignal(-1);
- X
- X if ( missed_open_sig == -1 || missed_lock_sig == -1 ||
- X missed_loadseg_sig == -1 || missed_execute_sig == -1 ||
- X missed_curdir_sig == -1 || missed_delete_sig == -1) {
- X fprintf(stderr, "SnoopDos: Can't allocate enough signals.\n");
- X cleanup(-1);
- X return;
- X }
- X
- X if (extfile) {
- X debugwin = Open(extfilename, MODE_NEWFILE);
- X if (!debugwin) {
- X fprintf(stderr, "SnoopDos: Can't open file %s for output.\n",
- X extfilename);
- X cleanup(-1);
- X return;
- X }
- X fprintf(debugwin, "\r\n" TITLE "\r\n\r\n");
- X } else {
- X debugwin = Open(DEFWINDOW TITLE, MODE_NEWFILE);
- X if (!debugwin) {
- X fprintf(stderr, "SnoopDos: Can't open display window.\n");
- X cleanup(-1);
- X return;
- X }
- X }
- X Close(stderr); stderr = NULL;
- X
- X if (!extfile) {
- X fprintf(debugwin, "\n"
- X "Type CTRL-E/CTRL-D to enable/disable snooping. Type CTRL-C to exit.\n\n");
- X };
- X fprintf(debugwin, HEADER);
- X
- X InitSemaphore(sem);
- X snooptask = FindTask(0L);
- X installdospatch();
- X
- X /*
- X * Now just sit processing messages
- X */
- X while (!done) {
- X int mask;
- X
- X#define SIGMASK (portsig | missed_open_sig | missed_lock_sig | \
- X missed_loadseg_sig | missed_execute_sig | \
- X missed_curdir_sig | missed_delete_sig | \
- X SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E)
- X
- X mask = Wait(SIGMASK);
- X
- X if (mask & SIGBREAKF_CTRL_C)
- X done = 1;
- X
- X if (mask & SIGBREAKF_CTRL_D) {
- X if (snoopactive) {
- X fprintf(debugwin,
- X"\nSnooping now disabled; type CTRL-E to enable it again.\r\n\r\n");
- X snoopactive = 0;
- X }
- X }
- X
- X if (mask & SIGBREAKF_CTRL_E) {
- X if (!snoopactive) {
- X fprintf(debugwin,
- X"Snooping now enabled; type CTRL-D to disable it again.\r\n\r\n%s", HEADER);
- X snoopactive = 1;
- X }
- X }
- X
- X if (mask & missed_open_sig)
- X missed |= MISSED_OPEN;
- X
- X if (mask & missed_lock_sig)
- X missed |= MISSED_LOCK;
- X
- X if (mask & missed_loadseg_sig)
- X missed |= MISSED_LOADSEG;
- X
- X if (mask & missed_execute_sig)
- X missed |= MISSED_EXECUTE;
- X
- X if (mask & missed_curdir_sig)
- X missed |= MISSED_CURDIR;
- X
- X if (mask & missed_delete_sig)
- X missed |= MISSED_DELETE;
- X
- X if (mask & portsig) {
- X MYMSG *msg;
- X
- X /*
- X * Note in the following, there is some slightly tricky
- X * stuff to handle the case where a DOS function calls
- X * another DOS function internally. Under 1.3, this doesn't
- X * happen, but it may under WB 2.0 and in addition, Jim
- X * Goodnow's handy Rez utility patches LoadSeg() so that
- X * it calls Open(). `nested' is true when a nested call
- X * like this happens, and in this case, process names are
- X * printed out prefixed by `> ' to indicate the nesting.
- X *
- X * The nesting is detected because an incoming Open/Lock/
- X * LoadSeg message will arrive when the cursor is positioned
- X * to print a Fail/Okay result from a previous call (i.e.
- X * col0 is false; the cursor is not in column 0). When a
- X * result arrives in and the cursor IS in column 0, then
- X * this must be the result from an earlier call so the
- X * nesting is ended. Note that the semaphores used ensures
- X * that this situation can only ever occur as a result of
- X * nesting; other tasks will always wait until they are
- X * properly in sync before sending messages to the main
- X * Snoopdos process.
- X *
- X * The more alert among you are probably saying something
- X * like "Ah, but what if SnoopDos is configured to display
- X * all DOS calls, even if it means forcing some tasks to
- X * sleep until SnoopDos can process them? Then, when a
- X * task calls LoadSeg() (say) and LoadSeg() calls Open(),
- X * Open() will sleep forever waiting for the semaphore
- X * Obtain()ed by LoadSeg() to become free again." Well,
- X * in fact, it won't, since exec's ObtainSemaphore() call
- X * will suceed even when the semaphore is in use, IF the
- X * caller is the task that owns the semaphore -- and in such
- X * a case, the caller will be the same task. (It took me a
- X * while to figure out exactly what things were working --
- X * it looked like I should get a serious lockup in certain
- X * circumstances).
- X *
- X */
- X while ((msg = (MYMSG *)GetMsg(myport)) != NULL) {
- X /*
- X * Get the name of the process/command for
- X * printing out if necessary.
- X */
- X static char namebuf[256];
- X UBYTE *procname = msg->process->pr_Task.tc_Node.ln_Name;
- X struct CommandLineInterface *cli = BTOC(msg->process->pr_CLI);
- X BPTR curdir = msg->process->pr_CurrentDir;
- X UBYTE *s;
- X UBYTE *filename;
- X int newname; /* If true, a new name was generated */
- X
- X if (!col0 && (msg->msgtype == MSG_OPEN ||
- X msg->msgtype == MSG_LOCK ||
- X msg->msgtype == MSG_LOADSEG ||
- X msg->msgtype == MSG_CURDIR ||
- X msg->msgtype == MSG_DELETE)) {
- X nested = 1;
- X fprintf(debugwin, TXT_NEST);
- X }
- X if (cli && cli->cli_Module) {
- X UBYTE *cliname = BTOC(cli->cli_CommandName);
- X if (*cliname > 0) {
- X /* Only use CLI name if it's not null */
- X strncpy(namebuf+2, cliname + 1, *cliname);
- X namebuf[*cliname+2] = '\0';
- X procname = namebuf + 2;
- X if (nested) {
- X /*
- X * If we're not at column 0, then we're
- X * calling this DOS function from within
- X * another DOS function so indent display
- X */
- X procname = namebuf;
- X procname[0] = '>';
- X procname[1] = ' ';
- X }
- X }
- X } else {
- X if (nested) {
- X sprintf(namebuf, "> %s", procname);
- X procname = namebuf;
- X }
- X }
- X
- X /*
- X * Now handle the message
- X */
- X filename = msg->data2; /* Standard file name */
- X newname = 0; /* No problems expanding it */
- X
- X switch (msg->msgtype) {
- X
- X case MSG_QUIT:
- X done = 1;
- X break;
- X
- X case MSG_GETOPTIONS:
- X memcpy(msg->data2, &settings, sizeof(SETTINGS));
- X break;
- X
- X case MSG_SETOPTIONS:
- X memcpy(&settings, msg->data2, sizeof(SETTINGS));
- X break;
- X
- X case MSG_OPEN:
- X if (msg->data1 == MODE_OLDFILE)
- X s = TXT_OLD;
- X else if (msg->data1 == MODE_NEWFILE)
- X s = TXT_NEW;
- X else if (msg->data1 == MODE_READWRITE)
- X s = TXT_R_W;
- X else
- X s = TXT_QM3;
- X
- X if (showfullpath) {
- X newname = makepath(fullname, curdir, msg->data2);
- X filename = fullname;
- X }
- X fprintf(debugwin, "%-21s %s %s%-39s %s ", procname,
- X TXT_OPEN, POINT(newname), filename, s);
- X col0 = 0;
- X break;
- X
- X case MSG_LOCK:
- X if (msg->data1 == ACCESS_READ)
- X s = TXT_SHAR;
- X else if (msg->data1 == ACCESS_WRITE)
- X s = TXT_EXCL;
- X else
- X s = TXT_QM4;
- X
- X if (showfullpath) {
- X newname = makepath(fullname, curdir, msg->data2);
- X filename = fullname;
- X }
- X fprintf(debugwin, "%-21s %s %s%-39s %s ", procname,
- X TXT_LOCK, POINT(newname), filename, s);
- X col0 = 0;
- X break;
- X
- X case MSG_LOADSEG:
- X if (showfullpath) {
- X newname = makepath(fullname, curdir, msg->data2);
- X filename = fullname;
- X }
- X fprintf(debugwin, "%-21s %s %s%-44s ", procname,
- X TXT_LOAD, POINT(newname), filename);
- X col0 = 0;
- X break;
- X
- X case MSG_EXECUTE:
- X fprintf(debugwin, "%-21s %s %s\r\n", procname,
- X TXT_EXEC, filename);
- X col0 = 1;
- X break;
- X
- X case MSG_CURDIR:
- X {
- X char *dirname = getlockpath(msg->data1);
- X int i = strlen(dirname);
- X
- X if (dirname[i-1] == '/')
- X dirname[i-1] = '\0';
- X fprintf(debugwin, "%-21s %s %s\r\n", procname,
- X TXT_CURDIR, dirname);
- X col0 = 1;
- X }
- X break;
- X
- X case MSG_DELETE:
- X if (showfullpath) {
- X newname = makepath(fullname, curdir, msg->data2);
- X filename = fullname;
- X }
- X fprintf(debugwin, "%-21s %s %s%-44s ", procname,
- X TXT_DELETE, POINT(newname), filename);
- X col0 = 0;
- X break;
- X
- X case MSG_LOCK_DONE:
- X case MSG_OPEN_DONE:
- X case MSG_LOADSEG_DONE:
- X case MSG_DELETE_DONE:
- X if (col0 && nested) {
- X fprintf(debugwin, "%-73s", TXT_DONE);
- X nested = 0;
- X }
- X if (msg->data1)
- X fprintf(debugwin, TXT_OKAY);
- X else
- X fprintf(debugwin, TXT_FAIL);
- X col0 = 1;
- X break;
- X }
- X ReplyMsg(msg);
- X }
- X }
- X
- X /*
- X * Finally, check if we missed a DOS function. If we did,
- X * AND we are in column 0, print out an appropriate message.
- X * Otherwise, wait until next time. This stops the display
- X * getting messed up when waiting to print a 'Fail' or 'Okay'.
- X */
- X if (missed) {
- X if (col0) {
- X if (missed & MISSED_OPEN)
- X fprintf(debugwin, "%s an Open()\r\n", TXT_WARN);
- X if (missed & MISSED_LOCK)
- X fprintf(debugwin, "%s a Lock()\r\n", TXT_WARN);
- X if (missed & MISSED_LOADSEG)
- X fprintf(debugwin, "%s a LoadSeg()\r\n", TXT_WARN);
- X if (missed & MISSED_EXECUTE)
- X fprintf(debugwin, "%s an Execute()\r\n", TXT_WARN);
- X if (missed & MISSED_CURDIR)
- X fprintf(debugwin, "%s a CurrentDir()\r\n", TXT_WARN);
- X if (missed & MISSED_DELETE)
- X fprintf(debugwin, "%s a DeleteFile()\r\n", TXT_WARN);
- X missed = MISSED_NONE;
- X }
- X }
- X }
- X
- X /*
- X * Remove the port from the public ports list; this stops any
- X * SnoopDos processes started up elsewhere from trying to
- X * communicate with us (which may happen if this process can't
- X * exit immediately).
- X */
- X RemPort(myport);
- X myport->mp_Node.ln_Name = NULL;
- X
- X /*
- X * Now remove the dospatch, reply to all messages currently
- X * pending and cleanup.
- X */
- X if (!uninstalldospatch()) {
- X /*
- X * Someone else has patched DOSbase so print a message for
- X * the user and keep trying every 5 seconds until we succeed.
- X */
- X int count = 0;
- X
- X fprintf(debugwin,
- X"\r\n"
- X"Someone else has patched dos.library so I'll have to wait until they quit."
- X"\r\n");
- X if (!extfile) {
- X fprintf(debugwin,
- X "This window will close shortly though to stop it from annoying you.\r\n");
- X }
- X
- X do {
- X Delay(250); /* Wait 5 seconds */
- X if (debugwin) {
- X count++;
- X if (count > 2) {
- X Close(debugwin);
- X debugwin = NULL;
- X }
- X }
- X } while (!uninstalldospatch());
- X }
- X
- X if (debugwin)
- X fprintf(debugwin, "\r\nSnoopDos terminated.\r\n");
- X
- X /*
- X * To make sure there is no code still executing in our task
- X * before we exit, we allocate the semaphore used to ensure
- X * exclusive access to the code, then wait a small time to allow
- X * the other task a chance to execute the final instruction or two
- X * left in our code after it releases the semaphore. This is not
- X * foolproof :-( but it's better than nothing.
- X */
- X {
- X MYMSG *msg;
- X while (msg = (MYMSG *)GetMsg(myport))
- X ReplyMsg(msg);
- X }
- X ObtainSemaphore(sem);
- X Delay(10); /* Wait 0.2 seconds */
- X cleanup(-1);
- X}
- X
- X/*
- X * main()
- X * ------
- X * Mainline. Parses the command line and, if necessary, kicks off the
- X * background task to do the real work.
- X */
- Xvoid main(int argc, char **argv)
- X{
- X int error = 0; /* True if error detected in cmd line */
- X int quit = 0; /* True if we want to quit */
- X int colsel = 0; /* True if colour option was specified */
- X
- X /*
- X * See if we are already active elsewhere; if yes, then read in
- X * the default settings used by that process.
- X */
- X
- X myport = FindPort(PORTNAME);
- X if (myport)
- X sendmsg(MSG_GETOPTIONS, 0, &settings);
- X
- X while (argc > 1 && argv[1][0] == '-') {
- X int val;
- X
- X /* Make -X == -x0 and -x == -x1 */
- X if (argv[1][1] >= 'a' && argv[1][2] != '0')
- X val = 1;
- X else
- X val = 0;
- X
- X switch (tolower(argv[1][1])) {
- X
- X case 'a': colour = val;
- X colsel = 1; break; /* Display ANSI colour */
- X case 'c': docurdir = val; break; /* Monitor CurrentDir() */
- X case 'd': dodelete = val; break; /* Monitor DeleteFile() */
- X case 'f': showfullpath = val; break; /* Show full filepath */
- X case 'g': doloadseg = val; break; /* Monitor LoadSeg() */
- X case 'h': error = 1; break; /* Just print help msg */
- X case 'l': dolock = val; break; /* Monitor Lock() */
- X case 'm': snoopactive = val; break; /* Actively monitoring */
- X case 'o': doopen = val; break; /* Monitor Open() */
- X case 'q': quit = 1; break; /* Ask SnoopDos to quit */
- X case 'r': error = 2; break; /* Report settings */
- X case 'w': sleepwait = val; break; /* Wait when necessary */
- X case 'x': doexecute = val; break; /* Monitor Execute() */
- X case 'z':
- X if (argv[1][2]) {
- X strcpy(extfilename, &argv[1][2]);
- X extfile = 1;
- X } else {
- X argv++;
- X argc--;
- X if (argc > 1) {
- X strcpy(extfile, argv[1]);
- X extfile = 1;
- X }
- X }
- X if (!extfile) {
- X printf(
- X "-z must be followed by a filename. Type SnoopDos -h for help.\n");
- X exit(5);
- X }
- X /*
- X * If outputting to a file, make colour off
- X * by default, rather than on.
- X */
- X if (colsel == 0)
- X colour = 0;
- X break;
- X
- X default:
- X printf("Unrecognised option %s. Type Snoopdos -h for help.\n",
- X argv[1]);
- X exit(5);
- X }
- X argv++; argc--;
- X }
- X
- X if (argc > 1)
- X error = 1;
- X
- X if (error) {
- X if (error == 1) {
- X printf(TITLE "\n\n"
- X"SnoopDos monitors calls made to various AmigaDOS functions by all processes\n"
- X"on the system. The following options are available. Use -x1 or just -x to\n"
- X"enable an option, -X or -x0 to disable that option. Current settings in (-)."
- X"\n\n");
- X } else
- X printf("Current SnoopDos settings:\n\n");
- X
- X#define O(x,y) printf(x, y ? "(on)" : "(off)")
- XO(" -a Use ANSI colour sequences %s\n", colour);
- XO(" -c Monitor CurrentDir() calls %s\n", docurdir);
- XO(" -d Monitor DeleteFile() calls %s\n", dodelete);
- XO(" -f Display full filename paths %s\n", showfullpath);
- XO(" -g Monitor LoadSeg() calls %s\n", doloadseg);
- XO(" -l Monitor Lock() calls %s\n", dolock);
- XO(" -m Globally enable/disable monitoring %s\n", snoopactive);
- XO(" -o Monitor Open() calls %s\n", doopen);
- XO(" -w Display all activity, sleeping if necessary %s\n", sleepwait);
- XO(" -x Monitor Execute() calls %s\n", doexecute);
- X
- X if (error == 1) {
- X printf("\n"
- X" -h Print out this help message\n"
- X" -q Tell SnoopDos to quit\n"
- X" -r Report current SnoopDos settings\n"
- X" -z% Output to file % (e.g. -zCON:0/0/640/100/SnoopDos or -zSER:)\n"
- X"\n");
- X }
- X cleanup(5);
- X }
- X
- X /*
- X * First see are we already installed. If so, send a copy of the
- X * updated settings to the background process, or send a QUIT
- X * message if the user wanted to quit.
- X */
- X if (myport) {
- X if (quit)
- X sendmsg(MSG_QUIT, 0, 0);
- X else
- X sendmsg(MSG_SETOPTIONS, 0, &settings);
- X cleanup(0);
- X }
- X
- X /*
- X * If user wanted to quit and we weren't already running, just
- X * quit without doing anything.
- X */
- X if (quit) {
- X printf("There is no background SnoopDos process to tell to quit!\n");
- X cleanup(0);
- X }
- X
- X /*
- X * Not installed, so install ourselves. First of all though, we
- X * kick ourselves into the background and return control to the
- X * calling CLI. We need to do this before we start creating ports
- X * and opening files, to prevent Exec and AmigaDOS getting
- X * confused about which task we are.
- X *
- X * Also open stderr channel for the new task to output fatal
- X * error messages to; the new task takes responsibility for closing
- X * this channel.
- X */
- X stderr = Open("*", MODE_NEWFILE);
- X if (!res("SnoopDos", 5, mainloop, 4000)) {
- X printf("Couldn't spawn background SnoopDos task.\n");
- X cleanup(10);
- X }
- X}
- X
- X/*
- X * NewOpen()
- X * ---------
- X * This is the new Open() code. It checks to see if the calling task
- X * is actually the SnoopDos task; if it is, then it essentially does
- X * nothing (this stops any possible deadlock occurring). Otherwise,
- X * it sends a message to the task with the pertinent info.
- X *
- X * If sleeping is disabled then if the semaphore isn't immediately
- X * available, a signal is sent to the Snoopdos task telling it that
- X * it's missed trapping a function.
- X */
- X__asm BPTR NewOpen(reg_d1 char *filename, reg_d2 int mode)
- X{
- X BPTR filehandle;
- X geta4();
- X if (snoopactive && doopen && FindTask(0) != snooptask) {
- X if (sleepwait)
- X ObtainSemaphore(sem);
- X else if (!AttemptSemaphore(sem)) {
- X Signal(snooptask, missed_open_sig);
- X return (CallOpen(filename, mode));
- X }
- X sendmsg(MSG_OPEN, mode, filename);
- X filehandle = CallOpen(filename, mode);
- X sendmsg(MSG_OPEN_DONE, filehandle, 0);
- X ReleaseSemaphore(sem);
- X return (filehandle);
- X } else {
- X return (CallOpen(filename, mode));
- X }
- X}
- X/*
- X * NewLock()
- X * ---------
- X * Replacement for Lock(), all the comments for NewOpen() apply
- X * equally here.
- X */
- X__asm BPTR NewLock(reg_d1 char *filename, reg_d2 int mode)
- X{
- X BPTR lock;
- X geta4();
- X if (snoopactive && dolock && FindTask(0) != snooptask) {
- X if (sleepwait)
- X ObtainSemaphore(sem);
- X else if (!AttemptSemaphore(sem)) {
- X Signal(snooptask, missed_lock_sig);
- X return (CallLock(filename, mode));
- X }
- X sendmsg(MSG_LOCK, mode, filename);
- X lock = CallLock(filename, mode);
- X sendmsg(MSG_LOCK_DONE, lock, 0);
- X ReleaseSemaphore(sem);
- X return (lock);
- X } else {
- X return (CallLock(filename, mode));
- X }
- X}
- X
- X/*
- X * NewLoadSeg()
- X * ------------
- X * Replacement for Lock(), all the comments for NewOpen() apply
- X * equally here.
- X */
- X__asm BPTR NewLoadSeg(reg_d1 char *filename)
- X{
- X BPTR seglist;
- X geta4();
- X if (snoopactive && doloadseg && FindTask(0) != snooptask) {
- X if (sleepwait)
- X ObtainSemaphore(sem);
- X else if (!AttemptSemaphore(sem)) {
- X Signal(snooptask, missed_loadseg_sig);
- X return (CallLoadSeg(filename));
- X }
- X sendmsg(MSG_LOADSEG, 0, filename);
- X seglist = CallLoadSeg(filename);
- X sendmsg(MSG_LOADSEG_DONE, seglist, 0);
- X ReleaseSemaphore(sem);
- X return (seglist);
- X } else {
- X return (CallLoadSeg(filename));
- X }
- X}
- X
- X/*
- X * NewExecute()
- X * ------------
- X * Replacement for Execute()
- X */
- X__asm LONG NewExecute(reg_d1 char *command, reg_d2 BPTR in, reg_d3 BPTR out)
- X{
- X geta4();
- X if (snoopactive && doexecute && FindTask(0) != snooptask) {
- X if (sleepwait)
- X ObtainSemaphore(sem);
- X else if (!AttemptSemaphore(sem)) {
- X Signal(snooptask, missed_execute_sig);
- X return(CallExecute(command, in, out));
- X }
- X sendmsg(MSG_EXECUTE, 0, command);
- X ReleaseSemaphore(sem);
- X }
- X return(CallExecute(command, in, out));
- X}
- X
- X/*
- X * NewCurrentDir()
- X * ---------------
- X * Replacement for CurrentDir()
- X */
- X__asm BPTR NewCurrentDir(reg_d1 BPTR newlock)
- X{
- X geta4();
- X if (snoopactive && docurdir && FindTask(0) != snooptask) {
- X if (sleepwait)
- X ObtainSemaphore(sem);
- X else if (!AttemptSemaphore(sem)) {
- X Signal(snooptask, missed_curdir_sig);
- X return(CallCurrentDir(newlock));
- X }
- X sendmsg(MSG_CURDIR, newlock, 0);
- X ReleaseSemaphore(sem);
- X }
- X return(CallCurrentDir(newlock));
- X}
- X
- X/*
- X * NewDeleteFile()
- X * ---------------
- X * Replacement for DeleteFile()
- X */
- X__asm LONG NewDeleteFile(reg_d1 char *filename)
- X{
- X LONG success;
- X geta4();
- X if (snoopactive && dodelete && FindTask(0) != snooptask) {
- X if (sleepwait)
- X ObtainSemaphore(sem);
- X else if (!AttemptSemaphore(sem)) {
- X Signal(snooptask, missed_delete_sig);
- X return(CallDeleteFile(filename));
- X }
- X sendmsg(MSG_DELETE, 0, filename);
- X success = CallDeleteFile(filename);
- X sendmsg(MSG_DELETE_DONE, success, 0);
- X ReleaseSemaphore(sem);
- X } else
- X return(CallDeleteFile(filename));
- X}
- END_OF_FILE
- if test 32250 -ne `wc -c <'snoopdos.c'`; then
- echo shar: \"'snoopdos.c'\" unpacked with wrong size!
- fi
- # end of 'snoopdos.c'
- fi
- echo shar: End of archive 2 \(of 2\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked both archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- --
- Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
- Mail comments to the moderator at <amiga-request@uunet.uu.net>.
- Post requests for sources, and general discussion to comp.sys.amiga.
-